home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
NOVA - For the NeXT Workstation
/
NOVA - For the NeXT Workstation.iso
/
SourceCode
/
DeveloperLabs
/
Lab2
/
Solution
/
CompositeView.m
< prev
next >
Wrap
Text File
|
1989-06-30
|
8KB
|
283 lines
// CompositeView implements a view with three horizontal, equal-sized areas.
// The left-most area is the "source," the middle area is the "destination,"
// and the right-most area is the "result." CompositeView assures that the
// contents of the result area is always generated by compositing the other
// two areas using the compositing mode set in the setOperator: method.
// It is also possible to change the contents, color, and alpha of the
// source and destination areas; see the methods setSourceGray:,
// setSourceAlpha:, etc.
// CompositeView written by Bruce Blumberg and Ali Ozer, NeXT Developer Support
#import "CompositeView.h"
#import <appkit/Bitmap.h>
#import <appkit/Control.h>
#import <appkit/Matrix.h>
#import <appkit/Window.h>
#import <dpsclient/wraps.h>
@implementation CompositeView
// The possible draw modes for the source.
#define TRIANGLE 0
#define CIRCLE 1
#define DIAMOND 2
#define HEART 3
#define FLOWER 4
// newFrame creates the view, initializes the rectangles that define the
// three areas described above, and creates the bitmaps used for rendering the
// source and destination bitmaps.
+newFrame:(const NXRect *)tF
{
// Create the view
self = [super newFrame:tF];
// Make rectangles for source, destination and result
sRect = bounds;
sRect.size.width /= 3.0;
dRect = sRect;
dRect.origin.x = sRect.size.width;
rRect = dRect;
rRect.origin.x = dRect.origin.x + dRect.size.width;
// Create bitmap for source image. Bitmaps are flipped by default;
// make sure we make ours not-flipped.
source = [Bitmap newSize:sRect.size.width :sRect.size.height
type:NX_UNIQUEBITMAP];
[source setFlip:NO];
// Now do the same for the destination...
destination = [Bitmap newSize:dRect.size.width :dRect.size.height
type:NX_UNIQUEBITMAP];
[destination setFlip:NO];
// Set the default operator and source picture. Also set default
// gray and alpha values. You will of course have to make sure
// the sliders in your Interface Builder window have the same values.
// (This is a problem; can you see a way to fix it?)
operator = NX_COPY;
sourcePicture = TRIANGLE;
sourceGray = 0.333; // dark gray
destGray = 0.666; // light gray
sourceAlpha = 1.0; // opaque
destAlpha = 1.0; // opaque
// Create the bitmap images using the initial values set above
[self drawSource];
[self drawDestination];
return self;
}
// drawSource creates the source image in the source bitmap. Note that
// drawSource does not render in the view; it renders in the bitmap only.
-drawSource
{
[source lockFocus];
PScompositerect (0.0, 0.0, sRect.size.width, sRect.size.height, NX_CLEAR);
PSsetgray(sourceGray);
PSsetalpha(sourceAlpha);
PSnewpath();
switch (sourcePicture) {
case TRIANGLE:
PSmoveto (0.0, 0.0);
PSlineto (0.0, sRect.size.height);
PSlineto (sRect.size.width, sRect.size.height);
break;
case CIRCLE:
PSscale (sRect.size.width, sRect.size.height);
PSarc (0.5, 0.5, 0.4, 0.0, 360.0); // diameter is 80% of area
break;
case DIAMOND:
PSmoveto (0.0, sRect.size.height / 2.0);
PSlineto (sRect.size.width / 2.0, 0.0);
PSlineto (sRect.size.width, sRect.size.height / 2.0);
PSlineto (sRect.size.width / 2.0, sRect.size.height);
break;
case HEART:
PSscale (sRect.size.width, sRect.size.height);
PSmoveto (0.5, 0.5);
PScurveto (0.3, 1.0, 0.0, 0.5, 0.5, 0.1);
PSmoveto (0.5, 0.5);
PScurveto (0.7, 1.0, 1.0, 0.5, 0.5, 0.1);
break;
case FLOWER:
PSscale (sRect.size.width, sRect.size.height);
PStranslate (0.5, 0.5);
PSmoveto (0.0, 0.0);
{int cnt;
for (cnt = 0; cnt < 6; cnt++) {
PSrotate (60.0);
PScurveto (0.4, 0.5, -0.4, 0.5, 0.0, 0.0);
}
}
break;
default:
break;
}
PSclosepath();
PSfill();
[source unlockFocus];
return self;
}
// drawDestination creates the destination image in the destination bitmap.
// Like drawSource, drawDestination only draws in the bitmap, not the view.
-drawDestination
{
[destination lockFocus];
PScompositerect (0.0, 0.0, dRect.size.width, dRect.size.height, NX_CLEAR);
PSsetgray(destGray);
PSsetalpha(destAlpha);
PSnewpath();
PSmoveto(dRect.size.width, 0.0);
PSlineto(dRect.size.width, dRect.size.height);
PSlineto(0.0, dRect.size.height);
PSclosepath();
PSfill();
[destination unlockFocus];
return self;
}
// setSourcePicture allows setting the picture to be drawn in the source
// bitmap. Buttons connected to this method should have tags that are
// set to the various possible pictures (see the "#define"s, above).
//
// After setting the sourcePicture instance variable, setSourcePicture redraws
// the bitmap and updates the view to reflect the new configuration.
-setSourcePicture:(id)ctl
{
sourcePicture = [ctl selectedTag];
[self drawSource];
[self display];
return self;
}
// The following four methods set the color or alpha parameters and update
// the source or destination bitmaps and the view to reflect the change.
-setSourceGray:(id)ctl
{
sourceGray = [ctl floatValue];
[self drawSource];
[self display];
return self;
}
-setDestGray:(id)ctl
{
destGray = [ctl floatValue];
[self drawDestination];
[self display];
return self;
}
-setSourceAlpha:(id)ctl
{
sourceAlpha = [ctl floatValue];
[self drawSource];
[self display];
return self;
}
-setDestAlpha:(id)ctl
{
destAlpha = [ctl floatValue];
[self drawDestination];
[self display];
return self;
}
// The operator method returns the operator currently in use.
-(int)operator {return operator;}
// setOperator sets the operator to be used in the compositing operations
// and updates the view to reflect the change. Note that setOperator needs
// to be connected to a row of buttons.
-setOperator:(id)sender
{
char *modeName;
switch ([sender selectedRow]) {
case 0: operator = NX_COPY; break;
case 1: operator = NX_CLEAR; break;
case 2: operator = NX_SOVER; break;
case 3: operator = NX_DOVER; break;
case 4: operator = NX_SIN; break;
case 5: operator = NX_DIN; break;
case 6: operator = NX_SOUT; break;
case 7: operator = NX_DOUT; break;
case 8: operator = NX_SATOP; break;
case 9: operator = NX_DATOP; break;
case 10: operator = NX_XOR; break;
case 11: operator = NX_PLUSD; break;
case 12: operator = NX_PLUSL; break;
default: break;
}
[self speedyDraw];
return self;
}
// drawSelf:: simply redisplays the contents of the view. The source and
// destination rectangles are updated from the bitmaps while the result
// rectangle is created by compositing the two bitmaps.
-drawSelf:(NXRect *)r :(int) count
{
// Erase the whole view
NXEraseRect(&bounds);
// Draw the source bitmap and then frame it with black
[source composite:NX_COPY toPoint:&sRect.origin];
PSsetgray(NX_BLACK);
NXFrameRect(&sRect);
// Draw the destination bitmap and frame it with black
[destination composite:NX_COPY toPoint:&dRect.origin];
PSsetgray(NX_BLACK);
NXFrameRect(&dRect);
// And now create the destination image and frame it with black as well
[destination composite:NX_COPY toPoint:&rRect.origin];
[source composite:operator toPoint:&rRect.origin];
PSsetgray(NX_BLACK);
NXFrameRect(&rRect);
return self;
}
// speedyDraw provides some efficiency in redisplaying the view by assuming
// that the source and the destination rectangles are already in place.
-speedyDraw
{
[self lockFocus];
NXEraseRect(&rRect);
[destination composite:NX_COPY toPoint:&rRect.origin];
[source composite:operator toPoint:&rRect.origin];
NXFrameRect(&rRect);
[self unlockFocus];
[[self window] flushWindow];
return self;
}
@end